﻿;/////////////////////////////////////////////////////////////;
;                                                             ;
;                SimpleDX11 Direct3D Procedures               ;
;                                                             ;
;                                                             ;
;                   (c) 2013 SimpleDX Team                    ;
;                                                             ;
;                         License: MIT                        ;
;                                                             ;
;/////////////////////////////////////////////////////////////;

;-//    Private Declarations    //

Declare SetScreenSwapChain()
Declare SetScreenDevice() 
Declare SetScreenDeviceContext()
Declare SetScreenRenderTargetView()
Declare SetScreenDepthStencilView()
Declare SetScreenDepthStencilBuffer()
Declare SetScreenDepthStencilState()
Declare SetScreenRasterState()
Declare SetScreenWorldMatrix()
Declare SetScreenProjectionMatrix()
Declare SetScreenOrthoMatrix()
Declare SetScreenViewMatrix()

;-//    Private structures    //
Structure Screen3D_Template
  *vTable
  *p.Screen3D
  
  
  *SwapChain.IDXGISwapChain
  *Device.ID3D11Device
  *DeviceContext.ID3D11DeviceContext
  *RenderTargetView.ID3D11RenderTargetView 
  *DepthStencilView.ID3D11DepthStencilView
  *DepthStencilBuffer.ID3D11Texture2D
  *DepthStencilState.ID3D11DepthStencilState 
  *EnabledStencilState.ID3D11DepthStencilState
  *RasterState.ID3D11RasterizerState
  *BlendingState.ID3D11BlendState
  *DisbledBlendingState.ID3D11BlendState
  
  *ProjectionMatrix.D3DMATRIX
  *WorldMatrix.D3DMATRIX  
  *OrthoMatrix.D3DMATRIX 
  *ViewMatrix.D3DMATRIX
  
  Array BlendFactor.f(3)
  
  ZBuffer.l
  *Color.D3DXCOLOR
EndStructure


;-//    Constructor    //

Procedure New_Screen3D()
  Protected *this.Screen3D_Template
 
  *this = AllocateMemory(SizeOf(Screen3D_Template))
  InitializeStructure(*this, Screen3D_Template)
  
  If *this
    *this\vTable = ?Screen3D_Class    
    *this\p = *this
         
    *this\SwapChain          = SetScreenSwapChain()
    *this\Device             = SetScreenDevice()
    *this\DeviceContext      = SetScreenDeviceContext()
    *this\RenderTargetView = SetScreenRenderTargetView()

    
    *this\DepthStencilView   = SetScreenDepthStencilView()
    *this\DepthStencilBuffer = SetScreenDepthStencilBuffer()
    *this\DepthStencilState  = SetScreenDepthStencilState()
    *this\RasterState        = SetScreenRasterState()       

    *this\WorldMatrix        = SetScreenWorldMatrix()
    *this\ProjectionMatrix   = SetScreenProjectionMatrix()
    *this\OrthoMatrix        = SetScreenOrthoMatrix()
    *this\ViewMatrix         = SetScreenViewMatrix()
    
    ; Create a DepthStencilState with depth enabled
    Protected EnabledStencilDesc.D3D11_DEPTH_STENCIL_DESC 
    EnabledStencilDesc\DepthEnable                  = #True
    EnabledStencilDesc\DepthWriteMask               = #D3D10_DEPTH_WRITE_MASK_ALL
    EnabledStencilDesc\DepthFunc                    = #D3D11_COMPARISON_LESS
    EnabledStencilDesc\StencilEnable                = #True
    EnabledStencilDesc\StencilReadMask              = $ff
    EnabledStencilDesc\StencilWriteMask             = $ff
    EnabledStencilDesc\FrontFace\StencilFailOp      = #D3D11_STENCIL_OP_KEEP
    EnabledStencilDesc\FrontFace\StencilDepthFailOp = #D3D11_STENCIL_OP_INCR
    EnabledStencilDesc\FrontFace\StencilPassOp      = #D3D11_STENCIL_OP_KEEP
    EnabledStencilDesc\FrontFace\StencilFunc        = #D3D11_COMPARISON_ALWAYS
    EnabledStencilDesc\BackFace\StencilFailOp       = #D3D11_STENCIL_OP_KEEP
    EnabledStencilDesc\BackFace\StencilDepthFailOp  = #D3D11_STENCIL_OP_DECR
    EnabledStencilDesc\BackFace\StencilPassOp       = #D3D11_STENCIL_OP_KEEP
    EnabledStencilDesc\BackFace\StencilFunc         = #D3D11_COMPARISON_ALWAYS      

    If *this\Device\CreateDepthStencilState(EnabledStencilDesc, @*this\EnabledStencilState)
      ProcedureReturn #False  
    EndIf
    
	  Protected BlendStateDescription.D3D11_BLEND_DESC
  	BlendStateDescription\RenderTarget[0]\BlendEnable           = #True
  	BlendStateDescription\RenderTarget[0]\SrcBlend              = #D3D11_BLEND_ONE
  	BlendStateDescription\RenderTarget[0]\DestBlend             = #D3D11_BLEND_INV_SRC_ALPHA
  	BlendStateDescription\RenderTarget[0]\BlendOp               = #D3D11_BLEND_OP_ADD
  	BlendStateDescription\RenderTarget[0]\SrcBlendAlpha         = #D3D11_BLEND_ONE
  	BlendStateDescription\RenderTarget[0]\DestBlendAlpha        = #D3D11_BLEND_ZERO
  	BlendStateDescription\RenderTarget[0]\BlendOpAlpha          = #D3D11_BLEND_OP_ADD
  	BlendStateDescription\RenderTarget[0]\RenderTargetWriteMask = $0f


    If *this\Device\CreateBlendState(BlendStateDescription, @*this\BlendingState)
      ProcedureReturn #False  
    EndIf    
    
    BlendStateDescription\RenderTarget[0]\BlendEnable           = #False
    
    If *this\Device\CreateBlendState(BlendStateDescription, @*this\DisbledBlendingState)
      ProcedureReturn #False  
    EndIf   
    
    *this\BlendFactor(0)    = 0.0
    *this\BlendFactor(1)    = 0.0
    *this\BlendFactor(2)    = 0.0
    *this\BlendFactor(3)    = 0.0
    
  	*this\ZBuffer = #False
  	
    ProcedureReturn *this
  EndIf  
  ProcedureReturn #False  
EndProcedure

Procedure Screen3D_GetSwapChain(*this.Screen3D_Template)
  ProcedureReturn *this\SwapChain
EndProcedure

Procedure Screen3D_GetDevice(*this.Screen3D_Template)
  ProcedureReturn *this\Device
EndProcedure

Procedure Screen3D_GetDeviceContext(*this.Screen3D_Template)
  ProcedureReturn *this\DeviceContext
EndProcedure

Procedure Screen3D_GetRenderTargetView(*this.Screen3D_Template)
  ProcedureReturn *this\RenderTargetView
EndProcedure

Procedure Screen3D_GetDepthStencilView(*this.Screen3D_Template)
  ProcedureReturn *this\DepthStencilView
EndProcedure

Procedure Screen3D_GetDepthStencilBuffer(*this.Screen3D_Template)
  ProcedureReturn *this\DepthStencilBuffer
EndProcedure

Procedure Screen3D_GetDepthStencilState(*this.Screen3D_Template)
  ProcedureReturn *this\DepthStencilState
EndProcedure

Procedure Screen3D_GetRasterState(*this.Screen3D_Template)
  ProcedureReturn *this\RasterState
EndProcedure

Procedure Screen3D_GetWorldMatrix(*this.Screen3D_Template)
  ProcedureReturn *this\WorldMatrix
EndProcedure

Procedure Screen3D_GetProjectionMatrix(*this.Screen3D_Template)
  ProcedureReturn *this\ProjectionMatrix
EndProcedure

Procedure Screen3D_GetOrthoMatrix(*this.Screen3D_Template)
  ProcedureReturn *this\OrthoMatrix
EndProcedure

Procedure Screen3D_GetViewMatrix(*this.Screen3D_Template)
  ProcedureReturn *this\OrthoMatrix
EndProcedure

Procedure Screen3D_TurnOnAlphaBlending(*this.Screen3D_Template)
  *this\DeviceContext\OMSetBlendState(*this\BlendingState, *this\BlendFactor(), $ffffffff)
EndProcedure

Procedure Screen3D_TurnOffAlphaBlending(*this.Screen3D_Template)
  *this\DeviceContext\OMSetBlendState(*this\DisbledBlendingState, *this\BlendFactor(), $ffffffff)
EndProcedure

Procedure Screen3D_Start3D(*this.Screen3D_Template)
  *this\DeviceContext\OMSetBlendState(*this\DisbledBlendingState, *this\BlendFactor(), $ffffffff)
  *this\DeviceContext\OMSetDepthStencilState(*this\EnabledStencilState, 1)
  *this\ZBuffer = #True
EndProcedure 

Procedure Screen3D_Stop3D(*this.Screen3D_Template)
  *this\DeviceContext\OMSetBlendState(*this\BlendingState, *this\BlendFactor(), $ffffffff)
  *this\DeviceContext\OMSetDepthStencilState(*this\DepthStencilState, 1)
  *this\ZBuffer = #False
EndProcedure 

;Returns the alpha component of a color value as a float
Procedure.f Screen3D_GetAlpha(*this.Screen3D_Template, Color.l)
    tmpC.l = ((Color >> 24) & $ff)  
    ProcedureReturn tmpC / 255
EndProcedure 

;Returns the blue component of a color value as a float
Procedure.f Screen3D_GetBlue(*this.Screen3D_Template, Color.l)
    tmpC.l = ((Color >> 16) & $ff)  
    ProcedureReturn tmpC / 255
EndProcedure 

;Returns the green component of a color value as a float
Procedure.f Screen3D_GetGreen(*this.Screen3D_Template, Color.l)
    tmpC.l = ((Color >> 8) & $ff)  
    ProcedureReturn tmpC / 255
EndProcedure 

;Returns the red component of a color value as a float
Procedure.f Screen3D_GetRed(*this.Screen3D_Template, Color.l)
    tmpC.l = (Color & $ff)  
    ProcedureReturn tmpC / 255
EndProcedure


Procedure Screen3D_GetZBufferStatus(*this.Screen3D_Template)
  ProcedureReturn *this\ZBuffer  
EndProcedure


Procedure Screen3D_Release(*this.Screen3D_Template)
  If *this\EnabledStencilState : *this\EnabledStencilState\Release() : EndIf
  ClearStructure(*this, Screen3D_Template)
  FreeMemory(*this)  
EndProcedure


;-//    Private procedures    //

; Grab the SwapChain pointer from the Screen
Procedure SetScreenSwapChain() 
  Protected *SwapChain
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_SwapChain
    !MOV EAX,DWord [_PB_Screen_SwapChain]
    !MOV DWord [p.p_SwapChain],EAX
  CompilerElse
    !extrn PB_Screen_SwapChain
    !MOV RAX,QWord [PB_Screen_SwapChain]
    !MOV QWord [p.p_SwapChain],RAX      
  CompilerEndIf  
  ProcedureReturn *SwapChain
EndProcedure

; Grab the Device pointer from the Screen
Procedure SetScreenDevice()
  Protected *Device
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_Device
    !MOV EAX,DWord [_PB_Screen_Device] 
    !MOV DWord [p.p_Device],EAX
  CompilerElse
    !extrn PB_Screen_Device
    !MOV RAX,QWord [PB_Screen_Device] 
    !MOV QWord [p.p_Device],RAX
  CompilerEndIf        
  ProcedureReturn *Device
EndProcedure

; Grab the DeviceContext pointer from the Screen
Procedure SetScreenDeviceContext()
  Protected *DeviceContext
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_DeviceContext
    !MOV EAX,DWord [_PB_Screen_DeviceContext] 
    !MOV DWord [p.p_DeviceContext],EAX 
  CompilerElse
    !extrn PB_Screen_DeviceContext
    !MOV RAX,QWord [PB_Screen_DeviceContext] 
    !MOV QWord [p.p_DeviceContext],RAX 
  CompilerEndIf 
  ProcedureReturn *DeviceContext
EndProcedure

; Grab the RenderTargetView pointer from the Screen
Procedure SetScreenRenderTargetView()
  Protected *RenderTargetView
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_RenderTargetView
    !MOV EAX,DWord [_PB_Screen_RenderTargetView]
    !MOV DWord [p.p_DepthStencilView],EAX 
  CompilerElse
    !extrn PB_Screen_RenderTargetView
    !MOV RAX,QWord [PB_Screen_RenderTargetView] 
    !MOV QWord [p.p_DepthStencilView],RAX 
  CompilerEndIf       
  ProcedureReturn *DepthStencilView
EndProcedure

; Grab the DepthStencilView pointer from the Screen
Procedure SetScreenDepthStencilView()
  Protected *DepthStencilView
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_DepthStencilView
    !MOV EAX,DWord [_PB_Screen_DepthStencilView] 
    !MOV DWord [p.p_DepthStencilView],EAX 
  CompilerElse
    !extrn PB_Screen_DepthStencilView
    !MOV RAX,QWord [PB_Screen_DepthStencilView] 
    !MOV QWord [p.p_DepthStencilView],RAX 
  CompilerEndIf  
  ProcedureReturn *DepthStencilView
EndProcedure

; Grab the DepthStencilBuffer pointer from the Screen
Procedure SetScreenDepthStencilBuffer()
  Protected *DepthStencilBuffer
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_DepthStencilBuffer
    !MOV EAX,DWord [_PB_Screen_DepthStencilBuffer] 
    !MOV DWord [p.p_DepthStencilBuffer],EAX 
  CompilerElse
    !extrn PB_Screen_DepthStencilBuffer
    !MOV RAX,QWord [PB_Screen_DepthStencilBuffer] 
    !MOV QWord [p.p_DepthStencilBuffer],RAX 
  CompilerEndIf  
  ProcedureReturn *DepthStencilBuffer  
EndProcedure  

; Grab the DepthStencilState pointer from the Screen
Procedure SetScreenDepthStencilState()
  Protected *DepthStencilState
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_DepthStencilState
    !MOV EAX,DWord [_PB_Screen_DepthStencilState] 
    !MOV DWord [p.p_DepthStencilState],EAX 
  CompilerElse
    !extrn PB_Screen_DepthStencilState
    !MOV RAX,QWord [PB_Screen_DepthStencilState] 
    !MOV QWord [p.p_DepthStencilState],RAX 
  CompilerEndIf  
  ProcedureReturn *DepthStencilState  
EndProcedure

; Grab the RasterState pointer from the Screen
Procedure SetScreenRasterState()
  Protected *RasterState
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_RasterState
    !MOV EAX,DWord [_PB_Screen_RasterState] 
    !MOV DWord [p.p_DepthStencilState],EAX 
  CompilerElse
    !extrn PB_Screen_RasterState
    !MOV RAX,QWord [PB_Screen_RasterState] 
    !MOV QWord [p.p_RasterState],RAX 
  CompilerEndIf  
  ProcedureReturn *RasterState  
EndProcedure

; Grab the WorldMatrix pointer from the Screen
Procedure SetScreenWorldMatrix()
  Protected *WorldMatrix
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_WorldMatrix
    !MOV EAX,DWord _PB_Screen_WorldMatrix
    !MOV DWord [p.p_WorldMatrix],EAX 
  CompilerElse       
    !extrn PB_Screen_WorldMatrix
    !MOV RAX,QWord PB_Screen_WorldMatrix 
    !MOV QWord [p.p_WorldMatrix],RAX  
   CompilerEndIf  
  ProcedureReturn *WorldMatrix
EndProcedure


; Grab the WorldMatrix pointer from the Screen
Procedure SetScreenProjectionMatrix()
  Protected *ProjectionMatrix
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_ProjectionMatrix
    !MOV EAX,DWord _PB_Screen_ProjectionMatrix
    !MOV DWord [p.p_ProjectionMatrix],EAX 
  CompilerElse       
    !extrn PB_Screen_ProjectionMatrix
    !MOV RAX,QWord PB_Screen_ProjectionMatrix 
    !MOV QWord [p.p_ProjectionMatrix],RAX  
   CompilerEndIf  
  ProcedureReturn *ProjectionMatrix
EndProcedure

; Grab the OrthoMatrix pointer from the Screen
Procedure SetScreenOrthoMatrix()
  Protected *OrthoMatrix
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_OrthoMatrix
    !MOV EAX,DWord _PB_Screen_OrthoMatrix
    !MOV DWord [p.p_OrthoMatrix],EAX 
  CompilerElse       
    !extrn PB_Screen_OrthoMatrix
    !MOV RAX,QWord PB_Screen_OrthoMatrix 
    !MOV QWord [p.p_OrthoMatrix],RAX  
   CompilerEndIf  
  ProcedureReturn *OrthoMatrix
EndProcedure

; Grab the OrthoMatrix pointer from the Screen
Procedure SetScreenViewMatrix()
  Protected *ViewMatrix
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86   
    !extrn _PB_Screen_ViewMatrix
    !MOV EAX,DWord _PB_Screen_ViewMatrix
    !MOV DWord [p.p_ViewMatrix],EAX 
  CompilerElse       
    !extrn PB_Screen_ViewMatrix
    !MOV RAX,QWord PB_Screen_ViewMatrix
    !MOV QWord [p.p_ViewMatrix],RAX  
   CompilerEndIf  
  ProcedureReturn *ViewMatrix
EndProcedure

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;-//    DataSection    //
DataSection
  Screen3D_Class:
  Data.i @Screen3D_GetSwapChain()
  Data.i @Screen3D_GetDevice()
  Data.i @Screen3D_GetDeviceContext()
  Data.i @Screen3D_GetRenderTargetView()
  Data.i @Screen3D_GetDepthStencilView()
  Data.i @Screen3D_GetDepthStencilBuffer()
  Data.i @Screen3D_GetDepthStencilState()
  Data.i @Screen3D_GetRasterState()
  Data.i @Screen3D_GetWorldMatrix()
  Data.i @Screen3D_GetProjectionMatrix()
  Data.i @Screen3D_GetOrthoMatrix()
  Data.i @Screen3D_GetViewMatrix()
  Data.i @Screen3D_TurnOnAlphaBlending()
  Data.i @Screen3D_TurnOffAlphaBlending()
  Data.i @Screen3D_Start3D()
  Data.i @Screen3D_Stop3D()
  Data.i @Screen3D_GetAlpha()
  Data.i @Screen3D_GetBlue()
  Data.i @Screen3D_GetGreen()
  Data.i @Screen3D_GetRed()
  Data.i @Screen3D_GetZBufferStatus()
  Data.i @Screen3D_Release()
EndDataSection
; IDE Options = PureBasic 5.20 beta 14 LTS (Windows - x64)
; CursorPosition = 121
; FirstLine = 90
; Folding = --------
; EnableUnicode
; EnableXP